/* Project Axium
 * CZlib.cpp
 */

#include <stdio.h>
#include <windows.h>
#include "CZLib.h"

unsigned long CZlib::compressTable[512];
char * CZlib::decompressTable[2556];

int CZlib::init(){
	FILE * fp;
	long size, i;

	fp = fopen("compress.dat", "rb");
	fread(CZlib::compressTable, sizeof(unsigned long), 512, fp);
	fclose(fp);

	fp = fopen("decompress.dat","rb");
	fseek(fp,0,SEEK_END);
	size = ftell(fp);
	rewind(fp);
	fread(CZlib::decompressTable, sizeof(char), size, fp);
	fclose(fp);

	for(i = 0; i < size/4; i++)
		if(CZlib::decompressTable[i] > (char *)255)
			CZlib::decompressTable[i] = CZlib::decompressTable[i] - 0x15b3aaa0 + (unsigned long)CZlib::decompressTable;

	return 0;
}

int CZlib::compress_sub(char * output, unsigned long var1, unsigned long cume, char * lookup1, unsigned long var2, unsigned long var3, unsigned long lookup2){
	if((cume + lookup2 + 7)/8 > var1)
		return -1;
	var1 = lookup2+var3;
	if((var1+7)/8 > var2){
		return -1;
	} else if(var3 < var1){
		lookup2 = cume - var3;
		for(; var3 < var1; var3++)
			output[(lookup2+var3)/8] = ((~(1<<((lookup2+var3)&7)))&output[(lookup2+var3)/8])+(((lookup1[var3/8]>>(var3&7))&1)<<((lookup2+var3)&7));
	}
	return 0;
}

int CZlib::compress(char * input, unsigned long var1, char * output, unsigned long var2, unsigned long * lookup){
	unsigned int i, cume = 0, tmp;
	unsigned long * ptr;

	tmp = (var2-1)*8;
	for(i = 0; i < var1 && var1; i++){
		if(lookup[input[i]+384] + cume < tmp){
			ptr = lookup+input[i]+128;
			compress_sub(output+1, var2-1, cume, (char *)ptr, 4, 0, lookup[input[i]+384]);
			cume += lookup[input[i]+384];
		} else if(var1+1 >= var2){
			memset(output, 0, (var2/4)+(var2&3));
			memset(output+1, var1, var1/4);
			memset(output+1+var1/4, (var1+1)*8, var1&3);
			return var1;
		} else
			return -1;
	}
	output[0] = 1;

	return (cume+8);
}

unsigned long CZlib::decompress(char * in, unsigned long inSize, char * out, unsigned long outSize, char ** table){
	unsigned long ** follow = (unsigned long **)table[0];
	unsigned long i, j=0;

	if(in[0] != 1)
		return -1;
	in++;
	
	for(i = 0; i < inSize ;i++){
		if((in[i/8]>>(i&7))&1)
			follow = (unsigned long **)follow[1];
		else
			follow = (unsigned long **)follow[0];
		if(follow[0] == 0){
			if(follow[1]==0){
				out[j] = (char)follow[3];
				if(++j >= outSize)
					return -1;
				follow = (unsigned long **)table[0];
			}
		}
	}
	return j;
}

unsigned long * CZlib::getCompressTable() {
	return compressTable;
}

char ** CZlib::getDecompressTable() {
	return decompressTable;
}